package cn.ges.movie.controller.system

import com.ges.common.config.autowired.UserId
import com.ges.common.util.IPHelper
import com.ges.common.vo.ReturnJsonVO
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.boot.web.servlet.error.ErrorController
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException
import org.springframework.security.web.firewall.RequestRejectedException
import org.springframework.stereotype.Controller
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.*
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException
import org.springframework.web.multipart.MaxUploadSizeExceededException
import java.io.IOException
import java.util.*
import javax.servlet.http.HttpServletRequest
import kotlin.collections.HashMap


/**
 * 系统基础controller
 * 处理错误相关信息等
 */
@Controller
open class BaseSystemController : ErrorController {

    private val log: Logger = LoggerFactory.getLogger(BaseSystemController::class.java)

    @ExceptionHandler(Exception::class)
    open fun exceptionHandler(request: HttpServletRequest, e: Exception): ReturnJsonVO {
        log.info("${request.requestURL} 参数转换失败 信息为 ${e.localizedMessage}")
        return ReturnJsonVO.badRequest("")
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException::class)
    open fun mismatchErrorHandler(request: HttpServletRequest, e: MethodArgumentTypeMismatchException): ReturnJsonVO {
        log.info("${request.requestURL} 参数转换失败 信息为 ${e.localizedMessage}")
        return ReturnJsonVO.badRequest
    }

    /**
     * 用户访问无权访问的接口异常捕获
     * 使用注解标注权限的方法的处理
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ExceptionHandler(AuthenticationCredentialsNotFoundException::class)
    open fun authenticationCredentialsNotFoundException(): ReturnJsonVO? {
        return ReturnJsonVO(403, null, "你不被允许访问该接口!")
    }

    /**
     * RequestRejectedException捕捉
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(RequestRejectedException::class)
    open fun requestRejectedExceptionException(): ReturnJsonVO? {
        return ReturnJsonVO(400, null, "URL不规范!")
    }

    /**
     * 用户上传文件过大的异常捕获
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MaxUploadSizeExceededException::class)
    open fun sizeLimitExceededException(): ReturnJsonVO? {
        return ReturnJsonVO(400, null, "上传文件过大")
    }

    /**
     * IOException
     */
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(IOException::class)
    open fun iOException(): ReturnJsonVO? {
        return ReturnJsonVO(304, null, "")
    }


    /**
     * 异常处理
     */
    @ResponseBody
    @RequestMapping("/error")
    open fun handleError(request: HttpServletRequest): ReturnJsonVO? {
        // val attributeNames = request.attributeNames
        // 获取statusCode:400,401,404,500
        val statusCode = (request.getAttribute("javax.servlet.error.status_code") as Int?) ?: 200
        val path = request.getAttribute("javax.servlet.forward.servlet_path") as String?
        val exception = request.getAttribute("org.springframework.web.servlet.DispatcherServlet.EXCEPTION") as Exception?
        // 有异常才进行记录
        exception?.let {
            log.info("请求[${path}] 发生了一个异常[${exception.javaClass.name}] ")
        }

        // 获取错误信息
        var error: String? = null
        val attribute = request.getAttribute("error")
        val auth = request.getAttribute("auth")
        if (attribute is String) {
            error = attribute
        }
        val errorMessage = request.getAttribute("org.springframework.boot.web.servlet.error.DefaultErrorAttributes.ERROR")

        // 如果有参数校验错误信息,返回该错误信息
        if (errorMessage is MethodArgumentNotValidException) {
            val allErrors = errorMessage.bindingResult.allErrors
            // 遍历获得所有校验错误信息
            val errorMsg = StringBuilder()
            if (allErrors.size > 0) {
                for (allError in allErrors) {
                    errorMsg.append(allError.defaultMessage).append(" ")
                }
            }
            if (errorMsg.isEmpty()) {
                return ReturnJsonVO(statusCode, null, "An error occurred but No errorMsg,")
            }
            log.info("An error occurred errorMsg:{}", errorMessage)
            return ReturnJsonVO(statusCode, null, "An error occurred")
        }

        if (statusCode == HttpStatus.NOT_FOUND.value() || statusCode == HttpStatus.METHOD_NOT_ALLOWED.value()) {
            return ReturnJsonVO(404, null, Optional.ofNullable(error).orElse("不存在的页面"))
        }
        if (statusCode == HttpStatus.FORBIDDEN.value()) {
            return ReturnJsonVO(403, null, Optional.ofNullable(error).orElse("没有权限"))
        }
        if (statusCode == HttpStatus.BAD_REQUEST.value()) {
            return ReturnJsonVO.badRequest
        }
        return if (statusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
            ReturnJsonVO.build(500, null, Optional.ofNullable(error).orElse("服务器繁忙 请稍后再试 错误代码:500"))
        } else {
            ReturnJsonVO.build(statusCode, null, error)
        }
    }

    override fun getErrorPath(): String? {
        return "error"
    }


    /**
     * 获得用户访问ip
     */
    @ResponseBody
    @RequestMapping(value = ["/ip/"], method = [RequestMethod.POST])
    open fun getIp(@UserId userId: Long?, @RequestHeader headers: HttpHeaders): ReturnJsonVO? {
        val hashMap = HashMap<String, Any?>()
        hashMap["ip"] = IPHelper.getIpAddr()
        hashMap["headers"] = headers
        return ReturnJsonVO.success(hashMap, "")
    }


}